﻿
using ChongJu.GlobalInfo;
using ChongJu.ModelManager.Rating;
using Public.Logger;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Public.Tools;
using System.IO.Compression;
using Newtonsoft.Json.Linq;

namespace ChongJu.ImageAnalyze.XCDNN
{
    public class TbcoRatingAnalyze : IAnalyzeBase
    {
        /// <summary>
        /// XCDNN指针
        /// </summary>
        private IntPtr intPtrXCDNN;

        public bool Init()
        {
            try
            {
                if (LoadModel() == false)
                {
                    Logger.Error("加载模型失败");
                    return false;
                }

                return true;
            }
            catch (Exception ex)
            {
                Logger.Error("初始化模型异常", ex);
                return false;
            }
        }

        public TbcoRatingAnalyze()
        {
        }

        public TbcoRatingAnalyze(bool init)
        {
            if (init)
                Init();
        }

        public RatingResultModel TaskAnalyze(Bitmap image, BitmapData imgData, float weight, bool isUp = true)
        {
            try
            {
                var result = TaskImageRating(image, imgData, intPtrXCDNN, weight, isUp);
                return result;
            }
            catch (Exception ex)
            {
                Logger.Error("分级异常", ex);
                return null;
            }
        }

        public string GetModelVersoin()
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                //XCDNNSDK.GetVersion(intPtrXCDNN, sb);

                return sb.ToString();
            }
            catch (Exception ex)
            {
                Logger.Error("获取模型版本异常", ex);
                return string.Empty;
            }
        }

        public string SaveSegmentImage(string dirPath, string levelCode, double weight)
        {
            try
            {
                if (Directory.Exists(dirPath) == false)
                    return null;

                var filePath = Path.Combine(dirPath, levelCode, $"{DateTime.Now.ToString("yyMMdd-HHssmm-fff")}--{weight}.png");

                if (Directory.Exists(Path.GetDirectoryName(filePath)) == false)
                    Directory.CreateDirectory(Path.GetDirectoryName(filePath));

                IntPtr init = Marshal.StringToHGlobalAnsi(filePath);
                var bol = TbcoRatingSDK.write_segmentation_img(intPtrXCDNN, init);
                return bol ? filePath : null;
            }
            catch (IOException ex)
            {
                Logger.Error("保存要上传的图片异常", ex);
                return null;
            }
        }
        
        public Bitmap GetSegmentImage(PixelFormat pixelFormat)
        {
            try
            {
                StringBuilder name = new StringBuilder("leafMat");
                int newWidth = 0, newHeight = 0, newStep = 0;
                IntPtr featureIntPtr = TbcoRatingSDK.get_feature_img_char(intPtrXCDNN, name, ref newWidth, ref newHeight, ref newStep);
                Bitmap featureImage = new Bitmap(newWidth, newHeight, newStep, pixelFormat, featureIntPtr);
                Bitmap newImage = new Bitmap(featureImage);
                featureImage.Dispose();
                TbcoRatingSDK.FreeResizedImage(featureIntPtr);
                return newImage;
            }
            catch (IOException ex)
            {
                Logger.Error("GetSegmentImage图片异常", ex);
                return null;
            }
        }

        public IntPtr GetSegmentationImg(int _width, int _height, IntPtr input, int step, ref int newWidth, ref int newHeight, ref int newStep, ref double angle, ref int x1, ref int y1, ref int w1, ref int h1, bool isUp = true)
        {
            if (isUp == true)
                return TbcoRatingSDK.Get_Segmentation_img(intPtrXCDNN,
                    _width,
                    _height,
                    3,
                    input,
                    step,
                    ref newWidth,
                    ref newHeight,
                    ref newStep,
                    ref angle,
                    ref x1,
                    ref y1,
                    ref w1,
                    ref h1
                    );
            else
                return TbcoRatingSDK.GetSegmentDnImg(intPtrXCDNN,
                    _width,
                    _height,
                    3,
                    input,
                    step,
                    ref newWidth,
                    ref newHeight,
                    ref newStep);
        }

        public void FreeImage(IntPtr data)
        {
            TbcoRatingSDK.FreeResizedImage(data);
        }

        public bool LoadCF()
        {
            if (intPtrXCDNN == IntPtr.Zero)
                return false;

            var bol = TbcoRatingSDK.LoadCFModel(intPtrXCDNN);
            return bol;
        }

        #region Private Function


        private bool LoadModel(bool isAgain = false)
        {
            try
            {
                bool bol = false;
                if (isAgain == false)
                {
                    intPtrXCDNN = TbcoRatingSDK.Init();      //创建实例
                    bol = TbcoRatingSDK.LoadCFModel(intPtrXCDNN); //第一步 顺序不能
                    bol = TbcoRatingSDK.LoadDLModel(intPtrXCDNN); //第二步
                }
                else
                    bol = TbcoRatingSDK.LoadCFModel(intPtrXCDNN);

                if (bol == false)
                    Logger.Error("C++版本分拣模型加载失败");

                if(bol == false)
                    Logger.Debug($"测试：---- 模型加载失败 {intPtrXCDNN}");
                else
                    Logger.Debug("测试：---- 模型加载完成");

                return bol;
            }
            catch (Exception ex)
            {
                Logger.Error("C++版本分拣模型加载异常", ex);
                return false;
            }
        }

        private RatingResultModel ImageRating(Bitmap bitmap0, IntPtr xcdnn, float weight)
        {
            try
            {
                var log = new JObject();
                Bitmap bitmap = bitmap0;

                BitmapData bitmapdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
                int label = 0;
                double prob = 0;
                double timeSpan = 0;
                StringBuilder labelNameBuilder = new StringBuilder(10);
                var xcdnnAnalyzeStartTime = DateTime.Now;
                log.Add($"xcdnn-analyze-img-start-time", xcdnnAnalyzeStartTime.ToString("HH:mm:ss fff"));
                TbcoRatingSDK.ExecuteGrading(xcdnn, bitmap.Width, bitmap.Height, 3,
                        bitmapdata.Scan0, bitmapdata.Stride, ref label, ref timeSpan, labelNameBuilder, weight);
                log.Add($"xcdnn-analyze-img-end-time", DateTime.Now.ToString("HH:mm:ss fff"));
                log.Add($"xcdnn-analyze-img-total-time", (DateTime.Now - xcdnnAnalyzeStartTime).TotalMilliseconds);
                //获取分拣dll的运行各阶段的耗时时间
                GetRatingDllTime(xcdnn, log);
                bitmap.UnlockBits(bitmapdata);
                //bitmap.Dispose();
                string ImageInfo = "";
                string labelName = labelNameBuilder.ToString();

                StringBuilder sbCode = new StringBuilder();
                TbcoRatingSDK.GetAisleName(intPtrXCDNN, label, sbCode);

                StringBuilder sbLog = new StringBuilder(500);
                TbcoRatingSDK.GetAdjustLog(xcdnn, sbLog);

                log.Add($"label", label);
                log.Add($"labelName", labelName);
                log.Add($"aisle", sbCode.ToString());
                RatingResultModel result = new RatingResultModel()
                {
                    Rating = label,
                    RatingName = labelName,
                    RatingCode = sbCode.ToString(),
                    Probability = prob,
                    Success = true,
                    Time = timeSpan,
                    ImageInfo = ImageInfo,
                    AnalyzeLog = log,
                    ModelLog = sbLog.ToString()
                };

                return result;
            }
            catch(Exception ex)
            {
                Logger.Error("解析图片异常", ex);
                return null;
            }
        }

        private RatingResultModel TaskImageRating(Bitmap image, BitmapData imageData, IntPtr xcdnn, float weight, bool isUp = true)
        {
            try
            {
                int label = 0;
                double prob = 0;
                double timeSpan = 0;
                StringBuilder labelNameBuilder = new StringBuilder();
                var xcdnnAnalyzeStartTime = DateTime.Now;
                if(isUp == false)
                {
                    int area = 0;
                    TbcoRatingSDK.ExecuteEachImageV1(xcdnn, image.Width, image.Height, 3, imageData.Scan0,ref area);
                    return null;
                }
                TbcoRatingSDK.ExecuteGrading(xcdnn, image.Width, image.Height, 3,
                        imageData.Scan0, imageData.Stride, ref label, ref timeSpan, labelNameBuilder, weight);
                //获取分拣dll的运行各阶段的耗时时间
                //GetRatingDllTime(xcdnn, log);
                image.UnlockBits(imageData);
                //bitmap.Dispose();
                string ImageInfo = "";
                string labelName = labelNameBuilder.ToString();

                StringBuilder sbCode = new StringBuilder();
                TbcoRatingSDK.GetAisleName(intPtrXCDNN, label, sbCode);

                StringBuilder sbLog = new StringBuilder(500);
                TbcoRatingSDK.GetAdjustLog(intPtrXCDNN, sbLog);

                RatingResultModel result = new RatingResultModel()
                {
                    Rating = label,
                    RatingName = sbCode.ToString(),
                    RatingCode = labelName,
                    Probability = prob,
                    Success = true,
                    Weight = weight,
                    Time = timeSpan,
                };

                return result;
            }
            catch (Exception ex)
            {
                Logger.Error("解析图片异常", ex);
                return null;
            }
        }

        /// <summary>
        /// 获取分拣dll的运行各阶段的耗时时间
        /// </summary>
        /// <param name="xcdnn"></param>
        /// <param name="log"></param>
        private void GetRatingDllTime(IntPtr xcdnn, JObject log)
        {
            try
            {
                StringBuilder dllTimerBuilder = new StringBuilder(300);
                TbcoRatingSDK.Get_time_consuming(xcdnn, dllTimerBuilder);
                if (dllTimerBuilder.Length <= 0 || string.IsNullOrEmpty(dllTimerBuilder.ToString()))
                    return;

                log.Merge(JObject.Parse(dllTimerBuilder.ToString()));
            }
            catch (Exception ex)
            {
                Logger.Error("=====GetRatingDllTime===== 获取模型耗时失败",ex);
            }
        }

        public bool LoadLocalModel(bool isAgin = false)
        {
            return LoadModel(isAgin);
        }

        /// <summary>
        /// 设置Dll是否打日志
        /// </summary>
        /// <param name="bol"></param>
        public void IsDllLogger(bool bol)
        {
            TbcoRatingSDK.SetLogSwitch(intPtrXCDNN, bol == true ? 1 : 0);
        }

        public void DisposeXCDNN()
        {
            TbcoRatingSDK.Dispose(intPtrXCDNN);
        }

        public void CalibraLightCamera(IntPtr imgDir, 
            int targetb, int targetg, int targetr,
            ref double gradb, ref double gradg, ref double gradr,
            ref int stepL, 
            ref int stepb, ref int stepg, ref int stepr, ref int sucesFlag)
        {
            TbcoRatingSDK.CalibraLightCamera(intPtrXCDNN, imgDir, 
                targetb, targetg, targetr,
                ref gradb, ref gradg, ref gradr,
                ref stepL, 
                ref stepb, ref stepg, ref stepr, ref sucesFlag);
        }

        public string GetModelName()
        {
            StringBuilder stringBuilder = new StringBuilder();
            TbcoRatingSDK.GetModelName(intPtrXCDNN, stringBuilder);
            return stringBuilder.ToString();
        }

        #endregion
    }
}
